package com.cn.xt.config;


import com.cn.xt.constants.Constants;
import com.cn.xt.service.CustomUserService;
import com.cn.xt.utils.JsonUtil;
import com.cn.xt.utils.RedisUtil;
import com.cn.xt.vo.bean.CustomUserBean;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.HashMap;

/**
 * 验证用户名密码正确后，生成一个token，并将token返回给客户端
 * 该类继承自UsernamePasswordAuthenticationFilter，重写了其中的2个方法
 * attemptAuthentication ：接收并解析用户凭证。
 * successfulAuthentication ：用户成功登录后，这个方法会被调用，我们在这个方法里生成token。
 * @author liuyu on 2021/1/14.
 */
public class JWTLoginFilter extends UsernamePasswordAuthenticationFilter {

  private CustomUserService customUserService;
  private AuthenticationManager authenticationManager;

  private RedisUtil redisUtil;
  public JWTLoginFilter(AuthenticationManager authenticationManager,CustomUserService customUserService,RedisUtil redisUtil) {
    this.authenticationManager = authenticationManager;
    this.customUserService=customUserService;
    this.redisUtil=redisUtil;
  }

  /**
   * 接收并解析用户凭证
   * @author liuyu on 2021/1/14.
   */
  @Override
  public Authentication attemptAuthentication(HttpServletRequest req,
                                              HttpServletResponse res) throws AuthenticationException {
    String username =  req.getParameter("username");
    String password = req.getParameter("password");
    UserDetails userDetails = customUserService.loadUserByUsername(username);
    return authenticationManager.authenticate(
        new UsernamePasswordAuthenticationToken(username, password,userDetails.getAuthorities()));
  }

  /**
   * 用户成功登录后，这个方法会被调用，我们在这个方法里生成token
   * @author liuyu on 2021/1/14.
   */
  @Override
  protected void successfulAuthentication(HttpServletRequest req,
                                          HttpServletResponse res,
                                          FilterChain chain,
                                          Authentication auth) throws IOException, ServletException {
    CustomUserBean user= ((CustomUserBean) auth.getPrincipal());

    String token = Jwts.builder()
            .setSubject(user.getUser().getUser().getId())
            //tocken过期时间为1天
            .setExpiration(new Date(System.currentTimeMillis() + 60 * 60 * 24 * 1000))
            .signWith(SignatureAlgorithm.HS512, "MyJwtSecret")
            .compact();
    res.setContentType("application/json;charset=UTF-8");
    res.addHeader("Authorization","Bearer " + token);
    res.addHeader(Constants.REDIS_USER_ID,Constants.REDISE_USER_KEY+"_"+user.getUser().getUser().getId());
    //登录成功后将用户信息保存至redis 5分钟
    redisUtil.set(Constants.REDISE_USER_KEY+"_"+user.getUser().getUser().getId(),user.getUser(),60 * 60 * 24 * 1000);
    //redisUtil.set(token,token,60 * 60 * 24 * 1000);
    //返回前端信息
    HashMap<String,Object> msg = new HashMap<>();
    msg.put(Constants.RESULT_MSG,Constants.HTTP_RES_CODE_200_VALUE);
    msg.put(Constants.REDISE_USER_KEY,user.getUser());
    msg.put("token","Bearer " + token);
    PrintWriter writer = res.getWriter();
    res.flushBuffer();
    writer.print(JsonUtil.objToJson(msg));
    writer.close();
  }

  /**
   * 用户失败后返回前端错误信息
   * @author liuyu on 2021/1/14.
   */
  @Override
  protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
    response.setHeader(Constants.RESULT_CODE, Constants.HTTP_RES_CODE_500_VALUE);
    response.setContentType("application/json;charset=UTF-8");
    HashMap<String,String> msg = new HashMap<>();
    PrintWriter writer = response.getWriter();
    response.flushBuffer();
    if(Constants.USER_PASSWORD_WRONG.equals(failed.getMessage())){
      msg.put(Constants.RESULT_MSG,"密码错误!");
      writer.print(JsonUtil.objToJson(msg));
      writer.close();
    }else {
      msg.put(Constants.RESULT_MSG,failed.getMessage());
      writer.print(JsonUtil.objToJson(msg));
      writer.close();
      response.setHeader(Constants.RESULT_MSG, failed.getMessage());
    }
    super.unsuccessfulAuthentication(request, response, failed);
  }
}

